<script setup lang='ts'>
import {
  computed,
  nextTick,
  onMounted,
  onUpdated,
  onUnmounted,
  ref
} from "vue";
import {
  NForm,
  FormInst,
  NFormItem,
  NInput,
  NButton,
  NPopover,
  useMessage
} from "naive-ui";
import { useScroll } from "../hooks/useScroll";
import { useBasicLayout } from "@/hooks/useBasicLayout";
import { useChatStore } from "@/store";
import { fetchChatAPI, fetchChatMessageAPI, fetchChatAPIProcess } from "@/api";
import { SvgIcon } from "@/components/common";
import * as emoji from "node-emoji";
import MarkdownIt from "markdown-it";
import mdKatex from "@traptitech/markdown-it-katex";
import mila from "markdown-it-link-attributes";
import hljs from "highlight.js";
import { t } from "@/locales";
import { copyToClip } from "@/utils/copy";

// debugger
let controller = new AbortController();

const message = useMessage();
const chatStore = useChatStore();
const { isMobile } = useBasicLayout();
const { scrollRef, scrollToBottom, scrollToBottomIfAtBottom } = useScroll();

const loading = ref<boolean>(false);
const chatNumber = ref<string>("");
const formRef = ref<FormInst | null>(null);
const textRef = ref<HTMLElement>();
const text = ref<string>("");
const showPrompt = ref(false);
const showLoading = ref<boolean>(false);

const formValue = ref<any>({
  subject: "",
  text1: "",
  text2: "",
  text3: "",
  text4: "",
  text5: ""
});

const disabled = computed(() => {
  return !(
    formValue.value?.subject.trim() &&
    (formValue.value?.text1.trim() ||
      formValue.value?.text2.trim() ||
      formValue.value?.text3.trim() ||
      formValue.value?.text4.trim() ||
      formValue.value?.text5.trim())
  );
});

const rules = {
  subject: {
    required: true,
    message: "请输入专利名称",
    trigger: ["input", "blur"]
  }
};

// 内容样式
const indexClass = computed(() => {
  let classes = ["w-[650px]"];
  if (isMobile.value) classes = ["w-full", "overflow-hidden"];
  return classes;
});

const promptClass = computed(() => {
  let classes = ["w-[650px]"];
  if (isMobile.value) classes = ["w-full", "overflow-hidden"];
  return classes;
});

// 禁止代码调试
// (() => {
//   function block() {
//     if (window.outerHeight - window.innerHeight > 200 || window.outerWidth - window.innerWidth > 200) {
//       document.body.innerHTML = "检测到非法调试,请关闭后刷新重试!";
//     }
//     setInterval(() => {
//       (function () {
//         return false;
//       }
//       ['constructor']('debugger')
//       ['call']());
//     }, 50);
//   }
//   try {
//     block();
//   } catch (err) { }
// })();

onMounted(() => {
  addCopyEvents();
});

onUpdated(() => {
  addCopyEvents();
});

onUnmounted(() => {
  if (loading.value) {
    controller.abort();
  }
  removeCopyEvents();
});

// 处理带表情文字
function parseEmoji(str: string) {
  return emoji.emojify(str);
}

// 一键优化
async function handleSubmit() {
  if (loading.value) return;
  let prompt = `你是一名企业科技管理人员，根据要求优化本发明解决的技术问题、该技术背景及相似方案、本技术缺点及需实现的目的、详细技术内容、技术创新点内容。
  专利名称为：${formValue.value.subject}\n 注意：专利名称不需要优化。
  要求字数多,至少要比目前的字数多 文字专业, 应专业、具体进行表达，请根据专利名称进行填写以下内容:`;
  if (formValue.value.text1) {
    prompt =
      prompt + `本发明解决的技术问题内容为：[${formValue.value.text1}]\n`;
  }
  if (formValue.value.text2) {
    prompt = prompt + `该技术背景及相似方案内容为：[${formValue.value.text2}]\n`;
  }
  if (formValue.value.text3) {
    prompt = prompt + `本技术缺点及需实现的目的内容为：[${formValue.value.text3}]\n`;
  }
  if (formValue.value.text4) {
    prompt = prompt + `详细技术内容为：[${formValue.value.text4}]\n`;
  }
  if (formValue.value.text5) {
    prompt = prompt + `技术创新点内容为：[${formValue.value.text4}]\n`;
  }
  fetchChat(prompt);
}

// 指定优化
async function handlePrompt(type: number) {
  if (loading.value) return;
  let prompt = `你是一名企业科技管理人员，根据要求优化本发明解决的技术问题、该技术背景及相似方案、本技术缺点及需实现的目的、详细技术内容、技术创新点内容。
  专利名称为：${formValue.value.subject}\n 注意：专利名称不需要优化。
  要求字数多,至少要比目前的字数多 文字专业, 应专业、具体进行表达，请根据专利名称进行填写以下内容:`;
  let content = "";
  let value = "";
  if (type == 1) {
    content = `本发明解决的技术问题内容为：[${formValue.value.text1}]`;
    value = formValue.value.text1;
  } else if (type == 2) {
    content = `该技术背景及相似方案内容为：[${formValue.value.text2}]`;
    value = formValue.value.text2;
  } else if (type == 3) {
    content = `本技术缺点及需实现的目的内容为：[${formValue.value.text3}]`;
    value = formValue.value.text3;
  } else if (type == 4) {
    content = `详细技术内容为：[${formValue.value.text4}]`;
    value = formValue.value.text4;
  } else if (type == 5) {
    content = `技术创新点内容为：[${formValue.value.text4}]`;
    value = formValue.value.text4;
  }
  if (!value || value == "") {
    message.warning("内容为空，无法优化");
    return;
  }

  prompt = prompt + content;
  fetchChat(prompt);
}

/** 发送聊天请求 */
async function fetchChat(message: string) {
  loading.value = true;
  showLoading.value = true;
  showPrompt.value = false;
  const chatData: Chat.ChatRequest = {
    systemPrompt: message,
    prompt: message
  };
  // 创建会话
  if (!chatNumber.value) {
    const chatRes = await fetchChatAPI(chatData);
    chatNumber.value = chatRes.data.chatNumber;
    await nextTick();
  }
  const messageData: Chat.MessageRequest = {
    chatNumber: chatNumber.value,
    model: chatStore.model,
    systemPrompt: message,
    prompt: message
  };
  // 发送内容
  const messageRes = await fetchChatMessageAPI(messageData);
  // 流式响应
  onConversation(chatNumber.value, messageRes.data);
}

/**
 * sse对话
 */
async function onConversation(chatNumber: string, conversationId: string) {
  controller = new AbortController();
  try {
    let lastText = "";
    text.value = "";
    const fetchChatAPIOnce = async () => {
      await fetchChatAPIProcess<Chat.ConversationResponse>({
        conversationId: conversationId,
        signal: controller.signal,
        onDownloadProgress: ({ event }) => {
          const xhr = event.target;
          const { responseText } = xhr;
          const lastIndex = responseText.lastIndexOf(
            "\n",
            responseText.length - 2
          );
          let chunk = responseText;
          if (lastIndex !== -1) {
            chunk = responseText.substring(lastIndex);
          }
          try {
            const data = JSON.parse(chunk);
            showLoading.value = false;
            showPrompt.value = true;
            text.value = lastText + (data.content ?? "");
            scrollToBottom();
          } catch (error) {
            console.info("回复错误:", error);
          }
        }
      });
    };
    await fetchChatAPIOnce();
  } catch (error) {
    text.value = "大模型回复失败";
  } finally {
    loading.value = false;
    showLoading.value = false;
    scrollToBottomIfAtBottom();
  }
}

/** 重新回复 */
// async function onRegenerate(messageId?: string | null) {
//   if (!messageId) return;
//   fetchChatMessageById(messageId).then((res: { data: { content: string } }) => {
//     prompt.value = res.data.content;
//     handleSubmit();
//   });
// }

const textValue = computed(() => {
  const value = text.value ?? "";
  return mdi.render(value);
});

const mdi = new MarkdownIt({
  html: false,
  linkify: true,
  highlight(code, language) {
    const validLang = !!(language && hljs.getLanguage(language));
    if (validLang) {
      const lang = language ?? "";
      return highlightBlock(
        hljs.highlight(code, { language: lang }).value,
        lang
      );
    }
    return highlightBlock(hljs.highlightAuto(code).value, "");
  }
});

mdi.use(mila, { attrs: { target: "_blank", rel: "noopener" } });
mdi.use(mdKatex, {
  blockClass: "katexmath-block rounded-md p-[10px]",
  errorColor: " #cc0000"
});

function highlightBlock(str: string, lang?: string) {
  return `<pre class="code-block-wrapper"><div class="code-block-header"><span class="code-block-header__lang">${lang}</span><span class="code-block-header__copy">${t(
    "chat.copyCode"
  )}</span></div><code class="hljs code-block-body ${lang}">${str}</code></pre>`;
}

async function handleCopy() {
  try {
    await copyToClip(text.value || "");
    message.success("复制成功");
  } catch {
    message.error("复制失败");
  }
}

function addCopyEvents() {
  if (textRef.value) {
    const copyBtn = textRef.value.querySelectorAll(".code-block-header__copy");
    copyBtn.forEach(btn => {
      btn.addEventListener("click", () => {
        const code = btn.parentElement?.nextElementSibling?.textContent;
        if (code) {
          copyToClip(code).then(() => {
            btn.textContent = "复制成功";
            setTimeout(() => {
              btn.textContent = "复制代码";
            }, 1000);
          });
        }
      });
    });
  }
}

function removeCopyEvents() {
  if (textRef.value) {
    const copyBtn = textRef.value.querySelectorAll(".code-block-header__copy");
    copyBtn.forEach(btn => {
      btn.removeEventListener("click", () => {});
    });
  }
}
</script>
<style lang="less">
@import url(../components/message/style.less);
</style>

<style scoped>
.input-form {
  border-radius: 8px;
  width: 380px;
}

.login-form {
  height: 45px;
  width: 600px;
  border-radius: 8px;
  font-size: 17px;
  font-weight: 500;
  display: flex;
  align-items: center;
}
</style>
<template>
  <div class="flex-col w-full h-full bg-slate-50 dark:bg-[#18181c]">
    <div class="h-20 pl-8 text-xl flex items-center">
      <!-- <img :src="logom" class="w-8 h-8 mr-2" /> -->
      <span>科研项目优化与分析</span>
    </div>
    <div class="flex mt-6">
      <!-- 表单填充 -->
      <div
        class="flex-col h-full bg-white dark:bg-[#24272e] mx-auto px-8 py-8 rounded-xl"
        :class="indexClass"
      >
        <div class="text-center text-3xl font-medium mb-2">技术交底书（专利）</div>
        <div class="text-center text-[15px] text-[#909090] mb-8">填写基础的内容信息，帮你快速生成专利相关文字。</div>
        <NForm
          ref="formRef"
          :model="formValue"
          :rules="rules"
          label-placement="left"
          label-width="auto"
        >
          <div>
            <NFormItem label="专利名称" path="subject">
              <NInput
                class="input-form"
                type="textarea"
                v-model:value="formValue.subject"
                placeholder="请输入专利名称"
              />
            </NFormItem>
          </div>
          <div class="flex items-center">
            <NFormItem label="本发明解决的技术问题">
              <NInput
                class="input-form"
                type="textarea"
                v-model:value="formValue.text1"
                placeholder="请输入本发明解决的技术问题"
              />
            </NFormItem>
            <NPopover
              raw
              trigger="hover"
              :show-arrow="true"
              :arrow-style="{ backgroundColor: 'rgb(100 116 139)' }"
            >
              <template #trigger>
                <div
                  class="ml-3 flex items-center justify-center w-[32px] h-[32px] bg-blue-50 dark:bg-[#24272e] rounded-2xl cursor-pointer"
                  @click="handlePrompt(1)"
                >
                  <SvgIcon icon="ri:send-plane-fill" class="text-2xl text-blue-600 mr-[3px]" />
                </div>
              </template>
              <div class="px-3 py-2 bg-slate-500 text-[#fff] rounded-md">优化</div>
            </NPopover>
          </div>
          <div class="flex items-center">
            <NFormItem label="该技术背景及相似方案">
              <NInput
                class="input-form"
                v-model:value="formValue.text2"
                type="textarea"
                placeholder="请输入该技术背景及相似方案"
              />
            </NFormItem>
            <NPopover
              raw
              trigger="hover"
              :show-arrow="true"
              :arrow-style="{ backgroundColor: 'rgb(100 116 139)' }"
            >
              <template #trigger>
                <div
                  class="ml-3 flex items-center justify-center w-[32px] h-[32px] bg-blue-50 dark:bg-[#24272e] rounded-2xl cursor-pointer"
                  @click="handlePrompt(2)"
                >
                  <SvgIcon icon="ri:send-plane-fill" class="text-2xl text-blue-600 mr-[3px]" />
                </div>
              </template>
              <div class="px-3 py-2 bg-slate-500 text-[#fff] rounded-md">优化</div>
            </NPopover>
          </div>
          <div class="flex items-center">
            <NFormItem label="本技术缺点及需实现的目的">
              <NInput
                class="input-form"
                v-model:value="formValue.text3"
                type="textarea"
                placeholder="请输入本技术缺点及需实现的目的"
              />
            </NFormItem>
            <NPopover
              raw
              trigger="hover"
              :show-arrow="true"
              :arrow-style="{ backgroundColor: 'rgb(100 116 139)' }"
            >
              <template #trigger>
                <div
                  class="ml-3 flex items-center justify-center w-[32px] h-[32px] bg-blue-50 dark:bg-[#24272e] rounded-2xl cursor-pointer"
                  @click="handlePrompt(3)"
                >
                  <SvgIcon icon="ri:send-plane-fill" class="text-2xl text-blue-600 mr-[3px]" />
                </div>
              </template>
              <div class="px-3 py-2 bg-slate-500 text-[#fff] rounded-md">优化</div>
            </NPopover>
          </div>
          <div class="flex items-center">
            <NFormItem label="详细技术内容">
              <NInput
                class="input-form"
                v-model:value="formValue.text4"
                type="textarea"
                placeholder="请输入详细技术内容"
              />
            </NFormItem>
            <NPopover
              raw
              trigger="hover"
              :show-arrow="true"
              :arrow-style="{ backgroundColor: 'rgb(100 116 139)' }"
            >
              <template #trigger>
                <div
                  class="ml-3 flex items-center justify-center w-[32px] h-[32px] bg-blue-50 dark:bg-[#24272e] rounded-2xl cursor-pointer"
                  @click="handlePrompt(4)"
                >
                  <SvgIcon icon="ri:send-plane-fill" class="text-2xl text-blue-600 mr-[3px]" />
                </div>
              </template>
              <div class="px-3 py-2 bg-slate-500 text-[#fff] rounded-md">优化</div>
            </NPopover>
          </div>
          <div class="flex items-center">
            <NFormItem label="技术创新点">
              <NInput
                class="input-form"
                v-model:value="formValue.text5"
                type="textarea"
                placeholder="请输入技术创新点"
              />
            </NFormItem>
            <NPopover
              raw
              trigger="hover"
              :show-arrow="true"
              :arrow-style="{ backgroundColor: 'rgb(100 116 139)' }"
            >
              <template #trigger>
                <div
                  class="ml-3 flex items-center justify-center w-[32px] h-[32px] bg-blue-50 dark:bg-[#24272e] rounded-2xl cursor-pointer"
                  @click="handlePrompt(5)"
                >
                  <SvgIcon icon="ri:send-plane-fill" class="text-2xl text-blue-600 mr-[3px]" />
                </div>
              </template>
              <div class="px-3 py-2 bg-slate-500 text-[#fff] rounded-md">优化</div>
            </NPopover>
          </div>
          <div class="flex justify-center">
            <NButton
              class="login-form"
              block
              type="primary"
              @click="handleSubmit()"
              :disabled="disabled"
              :loading="loading"
            >
              一键优化
              <SvgIcon icon="ri:check-line" style="color: #fff; margin-left:10px" />
            </NButton>
          </div>
        </NForm>
      </div>
      <div
        class="flex-col h-full bg-white dark:bg-[#24272e] mx-auto px-10 py-8 rounded-xl"
        :class="promptClass"
      >
        <div class="text-center text-3xl font-medium mb-2">AI优化{{ parseEmoji(':fire:') }}</div>
        <div class="text-center text-[15px] text-[#909090] mb-8">优化完成可复制下方内容，如不满意可以重新填写或选择重新优化。</div>
        <template v-if="showPrompt">
          <div
            id="scrollRef"
            ref="scrollRef"
            class="h-[510px] overflow-hidden overflow-y-auto no-scrollbar"
          >
            <div ref="textRef" class="leading-7 break-words text-[15px]">
              <div class="markdown-body" v-html="textValue" />
            </div>
          </div>
          <div class="flex justify-between mt-4">
            <div class="text-[#B0B7C0] text-xs">以上内容为AI生成，请自行辨别</div>
            <div>
              <NPopover
                raw
                trigger="hover"
                :show-arrow="true"
                :arrow-style="{ backgroundColor: 'rgb(100 116 139)' }"
              >
                <template #trigger>
                  <button
                    class="text-[18px] text-neutral-300 hover:text-neutral-800 dark:hover:text-neutral-300"
                    style="margin: 0;"
                    @click="handleCopy"
                  >
                    <SvgIcon icon="ri:file-copy-2-line" />
                  </button>
                </template>
                <div class="px-3 py-2 bg-slate-500 text-[#fff] rounded-md">复制</div>
              </NPopover>
            </div>
          </div>
        </template>
        <template v-else>
          <div class="w-full h-[574px] flex flex-col items-center justify-center">
            <template v-if="showLoading">
              <img src="@/assets/loading.gif" class="w-[300px] h-[300px]" />
            </template>
            <template v-else>
              <img src="@/assets/optimize.png" class="w-[380px] h-[320px]" />
              <div class="text-[#909090]">请在左侧输入内容，开始优化</div>
            </template>
          </div>
        </template>
      </div>
    </div>
  </div>
</template>
